const workerFactory  = require('child_process');
const path           = require('path');
const Const          = require('./common/const');
const log            = require('./util/log');

module.exports = {
    _WORKERS:[],
    /**
     * 激活下载线程
     */
    activeDownloadThread:function () {
        let count = 1;
        log.info(`Start Download Thread. Cnt:[${count}]`);
        let THIS_MODULE = this;
        let workerPath = path.join(__dirname, './download/worker.js');
        THIS_MODULE.forkProcess(workerPath,count);
    },

    /**
     * 开启子线程
     * @param workerPath  执行文件路径
     * @param pCnt        开启个数
     */
    forkProcess:function(workerPath,pCnt){
        let THIS_MODULE = this;
        let index = THIS_MODULE._WORKERS.length;
        for (let i = index; i < index + pCnt; ++i){
            THIS_MODULE._WORKERS.push(THIS_MODULE.activeWork(i,workerPath));
        }
    },

    /**
     * 激活工作线程
     * @param wid
     * @workerPath 文件路径
     * @returns {{process: workerFactory.fork, wid: *, time: number}}
     */
    activeWork: function(wid,workerPath){
        let THIS_MODULE = this;
        log.info(`Active worker:[${wid}] ! path:[${workerPath}] `);
        let worker = {
            wid:wid,
            path:workerPath,
            process:new workerFactory.fork(workerPath),
            heartBeatTimeStamp:(new Date()).getTime(),
        };
        worker.process.on('message',__onWorkerMsg);
        THIS_MODULE.sendMessage(worker,wid,Const._PROCESS_CODE._PIPE_MSG_RUN_MSG,{});
        return worker;


        /**
         * 接收Child process message.
         * @param msg
         * @private
         */
        function __onWorkerMsg(msg){

            let wid = msg.wid;

            if (msg.msg === Const._PROCESS_CODE._PIPE_MSG_WORKER_HEART_BEAT_RSP) {
                THIS_MODULE.onWorkerHeartBeatRsp(wid);
            } else {
                log.info('Recv undefined IPC cmd:' + msg.msg, config.LOG._LOG_LEVEL_ERROR);
            }

        }
    },
    /**
     * 心跳刷新
     * @param wid 进程ID
     */
    onWorkerHeartBeatRsp:function(wid){
        let THIS_MODULE = this;
        let worker = THIS_MODULE._WORKERS[wid];

        if(worker != null){
            log.debug(`Update Worker[${worker.wid }] length:[${THIS_MODULE._WORKERS.length}] heart beat timestamp.`);
            worker.heartBeatTimeStamp = (new Date()).getTime();
        }else{
            log.warn('Update Worker{' + wid + '} heart beat timestamp ERROR.');
        }
    },

    /**
     * 进程状态检查,根据worker.heartBeatTimeStamp判断是否大于超时时间,如果大于,停止此进程,重新启动
     */
    checkWorkersState:function(){
        let THIS_MODULE = this;

        for (let i in THIS_MODULE._WORKERS){
            let worker = THIS_MODULE._WORKERS[i];
            if(!worker){
                continue;
            }
            let timeElapse = (new Date()).getTime() - worker.heartBeatTimeStamp;

            log.debug(`Worker state check, heart beat time elapse: ${timeElapse} wid:${i}`);

            if(timeElapse > config.work.workTimeOut){
                log.info(`Worker [${worker.wid}] Seeking task timeOut:${timeElapse}, Restart... `);
                THIS_MODULE.reactiveSingleWorker(worker);
                log.info(`Worker length:${THIS_MODULE._WORKERS.length}`)
            }
        }
    },
    monitorWorkerState:function(){
        let THIS_MODULE = this;
        //进程监听,防止挂起
        setInterval(async () => {
            THIS_MODULE.checkWorkersState();
        },2000);
    },
    /**
     * 重启进程
     */
    reactiveSingleWorker:function(worker){
        let THIS_MODULE = this;
        THIS_MODULE.killWorker(worker.wid);
        THIS_MODULE._WORKERS[worker.wid] = THIS_MODULE.activeWork(worker.wid,worker.path);
        return THIS_MODULE._WORKERS[worker.wid];
    },
    sendMessage: function(worker, wid, msg, msgData){
        try{
            if(worker != null && worker.process != null){
                log.info(`Send worker[${wid}] message:[${msg}]`);
                worker.process.send({
                    wid:wid,
                    message:msg,
                    msgData:msgData
                })
            }else{
                log.err(`Send worker[${wid}] message error. NULL worker. msg:${msg}`);
            }
        }catch (e) {
            log.err(`Send worker[${wid}] message throw exception. errMsg:${e.message}`);
        }
    },

    killWorker: function(wid){
        let THIS_MODULE = this;
        let worker = THIS_MODULE._WORKERS[wid];
        log.info(`Kill worker wid[${wid}]`);
        worker.process.kill();
        worker.process = null;
    },





};

